home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2000 / MacHack 2000.toast / pc / The Hacks / MacHacksBug / Python 1.5.2c1 / Extensions / Imaging / PIL / TiffImagePlugin.py < prev    next >
Encoding:
Text File  |  2000-06-23  |  10.6 KB  |  433 lines

  1. #
  2. # The Python Imaging Library.
  3. # $Id: TiffImagePlugin.py,v 1.1.1.1 1998/08/18 13:07:54 sjoerd Exp $
  4. #
  5. # TIFF file handling
  6. #
  7. # TIFF is a flexible, if somewhat aged, image file format
  8. # originally defined by Aldus.  Although TIFF supports a wide
  9. # variety of pixel layouts and compression methods, the name
  10. # doesn't really stand for "thousands of incompatible file
  11. # formats," it just feels that way.
  12. #
  13. # To read TIFF data from a stream, the stream must be seekable.
  14. # For progressive decoding, make sure to use TIFF files where
  15. # the tag directory is placed first in the file.
  16. #
  17. # Notes:
  18. #    save(tiff) really needs more work:
  19. #    - data is currently written in a single strip
  20. #    - the "bits per sample" tag is not correctly written (?)
  21. #      when "samples per pixel" is not 1
  22. #    - the colormap is not written for palette images
  23. #
  24. # History:
  25. #    95-09-01 fl    Created
  26. #    96-05-04 fl    Handle JpegTables tag (tag 347, experimental)
  27. #    96-05-18 fl    Fixed palette support (tag 320)
  28. #    97-01-05 fl    Fixed predictor support (tag 317)
  29. #    97-08-27 fl    Added support for rational tags (from Perry Stoll)
  30. #    98-01-10 fl    Fixed seek/tell (from Jan Blom)
  31. #    98-07-15 fl    Use private names for internal variables
  32. #
  33. # Copyright (c) Secret Labs AB 1997-98.
  34. # Copyright (c) Fredrik Lundh 1995-97.
  35. #
  36. # See the README file for information on usage and redistribution.
  37. #
  38.  
  39. __version__ = "0.5"
  40.  
  41. import Image, ImageFile, ImagePalette
  42.  
  43. import string
  44.  
  45. #
  46. # --------------------------------------------------------------------
  47. # Read TIFF files
  48.  
  49. def l16(c):
  50.     return ord(c[0]) + (ord(c[1])<<8)
  51. def l32(c):
  52.     return ord(c[0]) + (ord(c[1])<<8) + (ord(c[2])<<16) + (ord(c[3])<<24)
  53.  
  54. def b16(c):
  55.     return ord(c[1]) + (ord(c[0])<<8)
  56. def b32(c):
  57.     return ord(c[3]) + (ord(c[2])<<8) + (ord(c[1])<<16) + (ord(c[0])<<24)
  58.  
  59.  
  60. COMPRESSION = {
  61.     # mapped from Compression (tag 259)
  62.     (1,): "raw",
  63.     (2,): "tiff_ccitt",
  64.     (3,): "group3",
  65.     (4,): "group4",
  66.     (5,): "tiff_lzw",
  67.     (6,): "tiff_jpeg", # obsolete
  68.     (7,): "jpeg",
  69.     (32771,): "tiff_raw_16", # 16-bit padding
  70.     (32773,): "packbits"
  71. }
  72.  
  73. OPEN = {
  74.     # mapped from Photometric Interpretation (262) and BitsPerSample (258)
  75.     (0, (1,)): ("1", "1;I"),
  76.     (0, (8,)): ("L", "L;I"),
  77.     (1, (1,)): ("1", "1"),
  78.     (1, (8,)): ("L", "L"),
  79.     (1, (16,)): ("L", "L;16B"),
  80.     (2, (8,8,8)): ("RGB", "RGB"),
  81.     (2, (8,8,8,8)): ("RGBA", "RGBA"),
  82.     (2, (16,16,16)): ("RGB", "RGB;16B"),
  83.     (2, (16,16,16,16)): ("RGB", "RGBA;16B"),
  84.     (3, (1,)): ("P", "P;1"),
  85.     (3, (2,)): ("P", "P;2"),
  86.     (3, (4,)): ("P", "P;4"),
  87.     (3, (8,)): ("P", "P"),
  88.     (5, (8,8,8,8)): ("CMYK", "CMYK"),
  89.     (6, (8,8,8)): ("RGB", "RGB"), # YCC, actually
  90. }
  91.  
  92.  
  93. def _accept(prefix):
  94.     return prefix[:2] in ["MM", "II"]
  95.  
  96.  
  97. class TiffImageFile(ImageFile.ImageFile):
  98.  
  99.     format = "TIFF"
  100.     format_description = "Aldus TIFF"
  101.  
  102.     def _open(self):
  103.     "Open the first image in a TIFF file"
  104.  
  105.     # Header
  106.     s = self.fp.read(8)
  107.     if s[:2] == "MM":
  108.         self.i16, self.i32 = b16, b32
  109.     elif s[:2] == "II":
  110.         self.i16, self.i32 = l16, l32
  111.     else:
  112.         raise SyntaxError, "not a TIFF file"
  113.     if self.i16(s[2:]) != 42:
  114.         raise SyntaxError, "unknown TIFF version"
  115.  
  116.     self.__first = self.__next = self.i32(s[4:])
  117.     self.__frame = 0
  118.  
  119.     self.__fp = self.fp # FIXME: hack
  120.  
  121.     self._seek(0)
  122.  
  123.     def seek(self, frame):
  124.     "Select a given frame as current image"
  125.  
  126.     self._seek(frame)
  127.     
  128.     def tell(self):
  129.     "Return the current frame number"
  130.  
  131.     return self._tell()
  132.  
  133.     def _seek(self, frame):
  134.  
  135.     self.fp = self.__fp
  136.     if frame < self.__frame:
  137.         # rewind file
  138.         self.__frame = 0
  139.         self.__next = self.__first
  140.     while self.__frame < frame:
  141.         self._gettags()
  142.         self.__frame = self.__frame + 1
  143.     self._gettags()
  144.     self._setup()
  145.  
  146.     def _tell(self):
  147.  
  148.     return self.__frame
  149.  
  150.     def _decoder(self, rawmode, layer):
  151.     "Setup decoder contexts"
  152.  
  153.     args = None
  154.     if rawmode == "P":
  155.         rawmode = "L"
  156.     if rawmode == "RGB" and self._planar_configuration == 2:
  157.         rawmode = rawmode[layer]
  158.     if self._compression == "raw":
  159.         args = (rawmode, 0, 1)
  160.     if self._compression in ["packbits", "tiff_lzw", "jpeg"]:
  161.         args = rawmode
  162.         if self._compression == "jpeg" and self.tag.has_key(347):
  163.         # Hack to handle abbreviated JPEG headers
  164.         self.tile_prefix = self.tag[347]
  165.         elif self._compression == "tiff_lzw" and self.tag.has_key(317):
  166.         # Section 14: Differencing Predictor
  167.         self.decoderconfig = (self.tag[317][0],)
  168.  
  169.     return args
  170.  
  171.     def _setup(self):
  172.     "Setup this image object based on current tags"
  173.  
  174.     # extract relevant tags
  175.     self._compression = COMPRESSION[self.tag[259]]
  176.     self._photometric_interpretation = self.tag[262][0]
  177.     self._planar_configuration = self.tag[284][0]
  178.  
  179.     if Image.DEBUG:
  180.         print "*** Summary ***"
  181.         print "- compression:", self._compression
  182.         print "- photometric_interpretation:", self._photometric_interpretation
  183.         print "- planar_configuration:", self._planar_configuration
  184.  
  185.     # size
  186.     xsize, ysize = self.tag[256][0], self.tag[257][0]
  187.     self.size = xsize, ysize
  188.  
  189.     if Image.DEBUG:
  190.         print "- size:", self.size
  191.  
  192.     # mode: check photometric interpretation and bits per pixel
  193.     try:
  194.         self.mode, rawmode = OPEN[(self._photometric_interpretation, 
  195.                     self.tag[258])]
  196.     except KeyError:
  197.         if Image.DEBUG:
  198.         print "- unknown photometric interpretation"
  199.         raise SyntaxError, "unknown pixel mode"
  200.  
  201.     if Image.DEBUG:
  202.         print "- raw mode:", rawmode
  203.         print "- pil mode:", self.mode
  204.  
  205.     self.info["compression"] = self._compression
  206.  
  207.     # build tile descriptors
  208.     x = y = l = 0
  209.     self.tile = []
  210.     if self.tag.has_key(273):
  211.         # striped image
  212.         h = self.tag[278][0]
  213.         w = self.size[0]
  214.         a = None
  215.         for o in self.tag[273]:
  216.         if not a:
  217.             a = self._decoder(rawmode, l)
  218.         self.tile.append(self._compression,
  219.                  (0, min(y, ysize), w, min(y+h, ysize)),
  220.                  o, a)
  221.         y = y + h
  222.         if y >= self.size[1]:
  223.             x = y = 0
  224.             l = l + 1
  225.             a = None
  226.     elif self.tag.has_key(324):
  227.         # tiled image
  228.         w = self.tag[322][0]
  229.         h = self.tag[323][0]
  230.         a = None
  231.         for o in self.tag[324]:
  232.         if not a:
  233.             a = self._decoder(rawmode, l)
  234.         # FIXME: this doesn't work if the image size
  235.         # is not a multiple of the tile size...
  236.         self.tile.append(self._compression,
  237.                  (x, y, x+w, y+h),
  238.                  o, a)
  239.         x = x + w
  240.         if x >= self.size[0]:
  241.             x, y = 0, y + h
  242.             if y >= self.size[1]:
  243.             x = y = 0
  244.             l = l + 1
  245.             a = None
  246.     else:
  247.         if Image.DEBUG:
  248.         print "- unknown data organization"
  249.         raise SyntaxError, "unknown data organization"
  250.  
  251.     # fixup palette descriptor
  252.     if self.mode == "P":
  253.         palette = map(lambda a: chr(a / 256), self.tag[320])
  254.         self.palette = ImagePalette.raw("RGB;L", string.join(palette, ""))
  255.  
  256.     # ----------------------------------------------------------------
  257.     # TIFF tag parser
  258.  
  259.     TYPES = {}
  260.  
  261.     def unpackString(self, data):
  262.     if data[-1:] == '\0':
  263.         data = data[:-1]
  264.     return data
  265.     TYPES[2] = (1, unpackString)
  266.  
  267.     def unpackShort(self, data):
  268.     l = []
  269.         for i in range(0, len(data), 2):
  270.         l.append(self.i16(data[i:i+2]))
  271.     return tuple(l)
  272.     TYPES[3] = (2, unpackShort)
  273.  
  274.     def unpackLong(self, data):
  275.     l = []
  276.         for i in range(0, len(data), 4):
  277.         l.append(self.i32(data[i:i+4]))
  278.     return tuple(l)
  279.     TYPES[4] = (4, unpackLong)
  280.  
  281.     def unpackRational(self, data):
  282.         l = []
  283.         for i in range(0, len(data), 8):
  284.             num   = self.i32(data[i:i+4])
  285.             denom = self.i32(data[i+4:i+8])
  286.         if denom == 0:
  287.             l.append(1.0)
  288.         else:
  289.             l.append(float(num)/float(denom))
  290.         return tuple(l)
  291.     TYPES[5] = (8, unpackRational)
  292.  
  293.     def unpackUndefined(self, data):
  294.     # Untyped data
  295.     return data
  296.     TYPES[7] = (1, unpackUndefined)
  297.  
  298.     def _gettags(self):
  299.     "Load a tag directory"
  300.  
  301.     if not self.__next:
  302.         raise EofError, "no more TIFF directories"
  303.  
  304.     self.fp.seek(self.__next)
  305.  
  306.     # Setup default tag values
  307.     self.tag = {
  308.         259: (1,),
  309.         284: (1,),
  310.     }
  311.  
  312.     # Load dictionary
  313.     for i in range(self.i16(self.fp.read(2))):
  314.  
  315.         s = self.fp.read(12)
  316.         tag, type = self.i16(s), self.i16(s[2:])
  317.  
  318.         if Image.DEBUG:
  319.         print "found", tag, type
  320.  
  321.         try:
  322.             size = self.TYPES[type][0] * self.i32(s[4:])
  323.         except KeyError:
  324.         if Image.DEBUG:
  325.             print "- unknown type", type
  326.             continue # ignore unknown type
  327.  
  328.         # Get and expand tag value
  329.         if size > 4:
  330.         here = self.fp.tell()
  331.             self.fp.seek(self.i32(s[8:]))
  332.         data = self.fp.read(size)
  333.         self.fp.seek(here)
  334.         else:
  335.             data = s[8:8+size]
  336.  
  337.         self.tag[tag] = self.TYPES[type][1](self, data)
  338.  
  339.     s = self.fp.read(4)
  340.     self.__next = self.i32(s[0:])
  341.  
  342.  
  343. #
  344. # --------------------------------------------------------------------
  345. # Write TIFF files
  346.  
  347. # little endian is default
  348.  
  349. def o16(i):
  350.     return chr(i&255) + chr(i>>8&255)
  351.  
  352. def o32(i):
  353.     return chr(i&255) + chr(i>>8&255) + chr(i>>16&255) + chr(i>>24&255)
  354.  
  355. SAVE = {
  356.     # mode: rawmode, bits per pixel, photometric interpretation
  357.     "1": ("1", 1, 1),
  358.     "L": ("L", 8, 1),
  359.     "RGB": ("RGB", 24, 2),
  360.     "P": ("P", 8, 3),
  361.     "A": ("L", 8, 4),
  362.     "CMYK": ("CMYK", 32, 5),
  363.     "YCC": ("YCC", 24, 6),
  364.     "LAB": ("LAB", 24, 8),
  365. }
  366.  
  367. def _save(im, fp, filename):
  368.  
  369.     try:
  370.     rawmode, bits, photo = SAVE[im.mode]
  371.     except KeyError:
  372.     raise IOError, "cannot write mode %s as TIFF" % im.mode
  373.  
  374.     # tiff header
  375.     fp.write("II" +            # intel byte order
  376.          o16(42) +            # version number
  377.          o32(8))            # offset to first tag directory
  378.  
  379.     tags = []
  380.  
  381.     # size
  382.     tags.append(256, im.size[0])    # width
  383.     tags.append(257, im.size[1])    # length
  384.  
  385.     # mode
  386.     if bits == 24:
  387.     tags.append(258, 8)        # bits per sample
  388.     tags.append(277, 3)        # samples per pixel
  389.     elif bits == 32:
  390.     tags.append(258, 8)        # bits per sample
  391.     tags.append(277, 4)        # samples per pixel
  392.     else:
  393.     tags.append(258, bits)
  394.     tags.append(277, 1)
  395.     if photo != 1:
  396.     tags.append(262, photo)        # photometric interpretation
  397.     #if im.mode == "P":
  398.     #    tags.append(320, None)        # colormap
  399.  
  400.     # data orientation
  401.     stride = (im.size[0]*bits+7)/8
  402.     tags.append(278, im.size[1])        # rows per strip (full image)
  403.     tags.append(279, stride*im.size[1]) # strip byte count
  404.  
  405.     # strip offset (must be appended last)
  406.     tags.append(273, 8 + 2 + len(tags) * 12 + 12 + 4)
  407.  
  408.     fp.write(o16(len(tags)))
  409.  
  410.     tags.sort() # write tags in correct order
  411.     for id, value in tags:
  412.     if value < 65536:
  413.         fp.write(o16(id) + o16(3) + o32(1) + o32(value))
  414.     else:
  415.         fp.write(o16(id) + o16(4) + o32(1) + o32(value))
  416.  
  417.     # end of IFD
  418.     fp.write("\000" * 4)
  419.  
  420.     ImageFile._save(im, fp, [("raw", (0,0)+im.size, 0, (rawmode, 0, 1))])
  421.  
  422. #
  423. # --------------------------------------------------------------------
  424. # Register
  425.  
  426. Image.register_open("TIFF", TiffImageFile, _accept)
  427. Image.register_save("TIFF", _save)
  428.  
  429. Image.register_extension("TIFF", ".tif")
  430. Image.register_extension("TIFF", ".tiff")
  431.  
  432. Image.register_mime("TIFF", "image/tiff")
  433.